package com.favccxx.search.domain;

import org.bson.types.ObjectId;
import org.reflections.ReflectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Repository
public class MongoCommonRepo implements CommonRepo<String> {

    @Autowired
    MongoTemplate mongoTemplate;

    @Override
    public <T> long delete(T obj) {
        return mongoTemplate.remove(obj).getDeletedCount();
    }

    @Override
    public <T> List<T> findAll(Class<T> clazz) {
        return mongoTemplate.findAll(clazz);
    }

    @Override
    public <T> T findById(Class<T> clazz, String id) {
        return mongoTemplate.findById(id, clazz);
    }

    @Override
    public <T> List<T> findByIds(Class<T> clazz, List<String> ids) {
        List<ObjectId> idList = ids.stream().map(ObjectId::new).collect(Collectors.toList());
        return mongoTemplate.find(Query.query(Criteria.where("id").in(idList)), clazz);
    }

    @Override
    public <T> T save(T obj) {
        return mongoTemplate.save(obj);
    }

    @Override
    public <T> long deleteById(String id, Class<T> clazz) {
        T obj = this.findById(clazz, id);
        if (obj != null) {
            this.delete(obj);
        }
        return 0;
    }

    @Override
    public <T> long update(String id, T newObj) {
        try {
            Query query = new Query(Criteria.where("id").is(id));
            Update update = new Update();
            Set<Field> allFields = ReflectionUtils.getAllFields(newObj.getClass());
            for (Field field : allFields) {
                if (field.getAnnotationsByType(Id.class).length == 0) {
                    field.setAccessible(true);
                    Object value = field.get(newObj);
                    update.set(field.getName(), value);
                }
            }
            return mongoTemplate.updateMulti(query, update, newObj.getClass()).getModifiedCount();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}
